{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Media File Analysis with FFprobe\n",
    "\n",
    "The `typed-ffmpeg` library provides functionality to analyze media files using FFmpeg's ffprobe utility. This allows you to extract detailed metadata about media files, including format information, stream details, and other relevant data.\n",
    "\n",
    "## Basic Usage\n",
    "\n",
    "The main functions for media file analysis are:\n",
    "\n",
    "- `probe()`: Returns metadata as a Python dictionary\n",
    "- `probe_obj()`: Returns metadata as a Python dataclass\n",
    "\n",
    "Here's a basic example:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'streams': [{'index': 0,\n",
       "   'codec_name': 'png',\n",
       "   'codec_long_name': 'PNG (Portable Network Graphics) image',\n",
       "   'codec_type': 'video',\n",
       "   'codec_tag_string': '[0][0][0][0]',\n",
       "   'codec_tag': '0x0000',\n",
       "   'width': 548,\n",
       "   'height': 131,\n",
       "   'coded_width': 548,\n",
       "   'coded_height': 131,\n",
       "   'closed_captions': 0,\n",
       "   'film_grain': 0,\n",
       "   'has_b_frames': 0,\n",
       "   'pix_fmt': 'rgba',\n",
       "   'level': -99,\n",
       "   'color_range': 'pc',\n",
       "   'color_space': 'gbr',\n",
       "   'refs': 1,\n",
       "   'r_frame_rate': '25/1',\n",
       "   'avg_frame_rate': '25/1',\n",
       "   'time_base': '1/25',\n",
       "   'disposition': {'default': 0,\n",
       "    'dub': 0,\n",
       "    'original': 0,\n",
       "    'comment': 0,\n",
       "    'lyrics': 0,\n",
       "    'karaoke': 0,\n",
       "    'forced': 0,\n",
       "    'hearing_impaired': 0,\n",
       "    'visual_impaired': 0,\n",
       "    'clean_effects': 0,\n",
       "    'attached_pic': 0,\n",
       "    'timed_thumbnails': 0,\n",
       "    'non_diegetic': 0,\n",
       "    'captions': 0,\n",
       "    'descriptions': 0,\n",
       "    'metadata': 0,\n",
       "    'dependent': 0,\n",
       "    'still_image': 0}}],\n",
       " 'format': {'filename': 'Digraph.gv.png',\n",
       "  'nb_streams': 1,\n",
       "  'nb_programs': 0,\n",
       "  'format_name': 'png_pipe',\n",
       "  'format_long_name': 'piped png sequence',\n",
       "  'size': '13680',\n",
       "  'probe_score': 99}}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import ffmpeg\n",
    "\n",
    "# Get basic information about a media file\n",
    "info = ffmpeg.probe(\"Digraph.gv.png\")\n",
    "print(info[\"streams\"][0][\"codec_type\"])\n",
    "info"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Available Information\n",
    "\n",
    "The probe functions can extract various types of information from media files:\n",
    "\n",
    "- Format information (container format, duration, bitrate)\n",
    "- Stream information (codecs, resolution, sample rate)\n",
    "- Program information\n",
    "- Chapter information\n",
    "- Frame and packet data\n",
    "\n",
    "You can control which information is extracted using the following parameters:\n",
    "\n",
    "- `show_format`: Show format/container info (default: True)\n",
    "- `show_streams`: Show streams info (default: True)\n",
    "- `show_programs`: Show programs info (default: False)\n",
    "- `show_chapters`: Show chapters info (default: False)\n",
    "- `show_frames`: Show frames info (default: False)\n",
    "- `show_packets`: Show packets info (default: False)\n",
    "- `show_program_version`: Show program version (default: False)\n",
    "- `show_library_versions`: Show library versions (default: False)\n",
    "- `show_pixel_formats`: Show pixel formats (default: False)\n",
    "- `show_error`: Show error information (default: False)\n",
    "\n",
    "## Example: Detailed Stream Analysis\n",
    "\n",
    "```python\n",
    "import ffmpeg\n",
    "\n",
    "# Get detailed information about streams\n",
    "info = ffmpeg.probe(\"video.mp4\", show_streams=True, show_format=True)\n",
    "\n",
    "# Print format information\n",
    "print(\"Format Information:\")\n",
    "print(f\"Format: {info['format']['format_name']}\")\n",
    "print(f\"Duration: {float(info['format']['duration']):.2f} seconds\")\n",
    "print(f\"Bitrate: {int(info['format']['bit_rate'])/1000:.0f} kbps\")\n",
    "\n",
    "# Print stream information\n",
    "print(\"\\nStream Information:\")\n",
    "for stream in info['streams']:\n",
    "    if stream['codec_type'] == 'video':\n",
    "        print(f\"\\nVideo Stream:\")\n",
    "        print(f\"  Codec: {stream['codec_name']}\")\n",
    "        print(f\"  Resolution: {stream['width']}x{stream['height']}\")\n",
    "        print(f\"  Frame Rate: {eval(stream['r_frame_rate']):.2f} fps\")\n",
    "    elif stream['codec_type'] == 'audio':\n",
    "        print(f\"\\nAudio Stream:\")\n",
    "        print(f\"  Codec: {stream['codec_name']}\")\n",
    "        print(f\"  Sample Rate: {stream['sample_rate']} Hz\")\n",
    "        print(f\"  Channels: {stream['channels']}\")\n",
    "```\n",
    "\n",
    "## Using probe_obj()\n",
    "\n",
    "The `probe_obj()` function returns the same information as `probe()`, but as a Python dataclass instead of a dictionary. This provides better type safety and IDE support:\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Streams: 1\n",
      "\n",
      "Video Stream:\n",
      "  Codec: png\n",
      "  Resolution: 548x131\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "ffprobeType(program_version=None, library_versions=None, pixel_formats=None, packets=None, frames=None, packets_and_frames=None, programs=None, streams=streamsType(stream=(streamType(disposition=streamDispositionType(default=0, dub=0, original=0, comment=0, lyrics=0, karaoke=0, forced=0, hearing_impaired=0, visual_impaired=0, clean_effects=0, attached_pic=0, timed_thumbnails=0, non_diegetic=0, captions=0, descriptions=0, metadata=0, dependent=0, still_image=0), tags=None, side_data_list=None, index=0, codec_name='png', codec_long_name='PNG (Portable Network Graphics) image', profile=None, codec_type='video', codec_tag='0x0000', codec_tag_string='[0][0][0][0]', extradata=None, extradata_size=None, extradata_hash=None, width=548, height=131, coded_width=548, coded_height=131, closed_captions=True, film_grain=True, has_b_frames=0, sample_aspect_ratio=None, display_aspect_ratio=None, pix_fmt='rgba', level=-99, color_range='pc', color_space='gbr', color_transfer=None, color_primaries=None, chroma_location=None, field_order=None, refs=1, sample_fmt=None, sample_rate=None, channels=None, channel_layout=None, bits_per_sample=None, initial_padding=None, id=None, r_frame_rate='25/1', avg_frame_rate='25/1', time_base='1/25', start_pts=None, start_time=None, duration_ts=None, duration=None, bit_rate=None, max_bit_rate=None, bits_per_raw_sample=None, nb_frames=None, nb_read_frames=None, nb_read_packets=None),)), chapters=None, format=formatType(tags=None, filename='Digraph.gv.png', nb_streams=1, nb_programs=0, nb_stream_groups=None, format_name='png_pipe', format_long_name='piped png sequence', start_time=None, duration=None, size=13680, bit_rate=None, probe_score=99), error=None)"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import ffmpeg\n",
    "\n",
    "# Get information as a dataclass\n",
    "info = ffmpeg.probe_obj(\"Digraph.gv.png\")\n",
    "\n",
    "# Access information using dot notation\n",
    "print(f\"Streams: {len(info.streams.stream)}\")\n",
    "\n",
    "# Access stream information\n",
    "for stream in info.streams.stream:\n",
    "    if stream.codec_type == \"video\":\n",
    "        print(\"\\nVideo Stream:\")\n",
    "        print(f\"  Codec: {stream.codec_name}\")\n",
    "        print(f\"  Resolution: {stream.width}x{stream.height}\")\n",
    "info"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "## Additional Options\n",
    "\n",
    "Both `probe()` and `probe_obj()` support additional options:\n",
    "\n",
    "- `cmd`: Path or name of the ffprobe executable (default: \"ffprobe\")\n",
    "- `timeout`: Maximum time in seconds to wait for ffprobe to complete (default: None, wait indefinitely)\n",
    "- Additional ffprobe command line parameters can be passed as keyword arguments\n",
    "\n",
    "Example with additional options:\n",
    "\n",
    "```python\n",
    "import ffmpeg\n",
    "\n",
    "# Get information with custom options\n",
    "info = ffmpeg.probe(\n",
    "    \"video.mp4\",\n",
    "    cmd=\"/usr/local/bin/ffprobe\",  # Custom ffprobe path\n",
    "    timeout=30,  # 30 second timeout\n",
    "    loglevel=\"quiet\",  # Suppress ffprobe output\n",
    "    show_frames=True,  # Include frame information\n",
    "    show_packets=True  # Include packet information\n",
    ")\n",
    "```\n",
    "\n",
    "## Error Handling\n",
    "\n",
    "The probe functions will raise exceptions in case of errors:\n",
    "\n",
    "- `FFMpegExecuteError`: If ffprobe returns a non-zero exit code\n",
    "- `subprocess.TimeoutExpired`: If the timeout is reached before ffprobe completes\n",
    "\n",
    "Example of error handling:\n",
    "\n",
    "```python\n",
    "import ffmpeg\n",
    "from ffmpeg.exceptions import FFMpegExecuteError\n",
    "\n",
    "try:\n",
    "    info = ffmpeg.probe(\"nonexistent.mp4\")\n",
    "except FFMpegExecuteError as e:\n",
    "    print(f\"Error executing ffprobe: {e}\")\n",
    "    print(f\"Command: {e.cmd}\")\n",
    "    print(f\"Return code: {e.retcode}\")\n",
    "    print(f\"Error output: {e.stderr.decode()}\")\n",
    "```\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "```python\n",
    "import ffmpeg\n",
    "from ffmpeg.exceptions import FFMpegExecuteError\n",
    "\n",
    "try:\n",
    "    info = ffmpeg.probe(\"nonexistent.mp4\")\n",
    "except FFMpegExecuteError as e:\n",
    "    print(f\"Error executing ffprobe: {e}\")\n",
    "    print(f\"Command: {e.cmd}\")\n",
    "    print(f\"Return code: {e.retcode}\")\n",
    "    print(f\"Error output: {e.stderr.decode()}\")\n",
    "```\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
